// 封装axios的实例对象，共享出一个拥有独立URL的实例化axios
import axios from "axios";

import { Toast } from 'vant'; // 导入vant的轻提示

import store from "@/store";
import router from "@/router";

console.log("baseURL::", process.env.VUE_APP_BASE_URL);

// 2. 调用axos.create得到axios的实例对象
const request = axios.create({
    baseURL: process.env.VUE_APP_BASE_URL // 独立的axios
})

// 给 request 这个axios的实例对象绑定请求和响应拦截器

// 添加请求拦截器
// 发送请求没有错误，调用第一个回调函数
// 发送请求有错误，调用第二个回调函数
request.interceptors.request.use(function (config) {

    // 在发送请求之前做些什么
    // config 会得到 request 的配置对象
    // { url: "", method: "POST", data: { id: 1 } }
    // 所以可以给这个配置对象添加 headers 节点，用于携带 token

    // 如果这个配置对象没有 headers 节点，axios会自动给添加一个
    // 但是给headers添加属性的时候，要注意不要造成覆盖

    // null 的属性如果点出来就会报错,所以先加一层判断
    if (store.state.user && store.state.user.token && !config.headers.Authorization) {

        // && !config.headers.Authorization 不是用来阻止  error.config.headers.Authorization = "" 这句话的
        // 使用 refresh_token 发送刷新 token 的请求不能进入到这个判断里来，因为这里使用token对请求进行重新修饰

        config.headers.Authorization = `Bearer ${store.state.user.token}`

    }

    return config;
}, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
});

// 添加响应拦截器
request.interceptors.response.use(function (response) {
    // 2xx 范围内的状态码都会触发该函数。
    // 调用
    console.log(response.data);

    return response.data || response;
}, async function (error) {
    // 超出 2xx 范围的状态码都会触发该函数。

    if (error.response) {
        // token失效，主动退出
        // 有响应体
        if (error.response.status === 401) {

            // 旧token
            let user = store.state.user

            if (user && user.refresh_token) { // 放置 user 是一个 null 从而报错
                // 刷新token
                try {
                    // res 得到最新的token
                    let res = await request({
                        method: "PUT",
                        url: "/v1_0/authorizations",
                        headers: {
                            Authorization: `Bearer ${user.refresh_token}` // 重新发送请求，使用 refresh_token
                        }
                    })

                    // 拿到新token，刷新vuex的数据
                    store.commit('setUser', {
                        token: res.data.token,
                        refresh_token: user.refresh_token
                    })

                    // 重新调用原来的接口
                    // error.config 就是原来的axios调用
                    error.config.headers.Authorization = "" // 清空原来的url的请求头
                    // 接下来要求再经过一次请求拦截器，给绑上新的Authorization

                    return request(error.config)
                } catch (error) {
                    // 刷新失败也要清空
                    store.commit('setUser', null)
                    // 跳转到登录
                    router.push("/login")
                }
            } else {
                // refresh_token 过期
                // 清空token
                store.commit('setUser', null)
                // 跳转到登录
                router.push("/login")
            }
        };


        Toast.fail(error.response.data.message); // 业务错误
    } else {
        Toast.fail("网络异常"); // 断网
    }

    return Promise.reject(error); // 这个错误是给外部
});

// 3. 导入创建好的axios实例对象，供其他模块使用发送网络请求
export default request

// util 工具放置一些工厂函数，用来制造一些符合预期的独立对象或者函数